package com.tnsw.noxnox.settopbox;

import java.util.ArrayList;
import java.util.Set;

import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.tnsw.coreutils.AsyncManager;
import com.tnsw.coreutils.http.THttpBase;
import com.tnsw.coreutils.http.THttpGet;
import com.tnsw.coreutils.http.THttpListener;

import android.content.Context;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.AsyncTask;
import android.util.Log;

public class PortScanner implements THttpListener {
	
	public static String EMULATOR_PREFIX = "192.168.1.";
	//public static String EMULATOR_PREFIX = "localhost";
	private String tag = "PortScanner";
	private Context context;
	
	private int chunkSize = 5;
	private int soTimeout = 3000;				// milliseconds
	private int connectionTimeout = 3000;		// milliseconds
	
	private PortScannerListener listener;
	
	private int count = 0;
	private String ipBase;
	private ArrayList<String> arrGoodIPs;
	private boolean isCancelled = false;
	
	private AsyncManager asyncManager;
	
	public PortScanner(Context context) {
		this.context = context;
		this.asyncManager = AsyncManager.getInstance();
		
		String currentIP = THttpBase.getWiFiIPAddress(context);
		if (currentIP.equals("") == false) {
			String ips[] = currentIP.split("\\.");
			this.ipBase = ips[0] + "." + ips[1] + "." + ips[2] + ".";
		}
		
		Log.d(tag, "currentIP=" + currentIP + ", ipBase=" + ipBase);
		this.asyncManager.appendNetworkLog("currentIP=" + currentIP + ", ipBase=" + ipBase);
		WifiManager wifi = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
		Log.d(tag, "isWifiEnabled=" + wifi.isWifiEnabled());
		Log.d(tag, "getWifiState()=" + wifi.getWifiState());
				
		this.arrGoodIPs = new ArrayList<String>();
		//this.ipBase = "202.57.128.";
		
	}
	
	public void cancel() {
		this.isCancelled = true;
	}
	
	private void singleScan(String sessionName, String url) {
		HttpParams params = new BasicHttpParams();
		
		HttpConnectionParams.setConnectionTimeout(params, this.connectionTimeout);
		HttpConnectionParams.setSoTimeout(params, this.soTimeout);
		HttpClient hc = new DefaultHttpClient(params);
			
		THttpGet h = new THttpGet(this.context, url);
		h.setSessionName(sessionName);
		h.setHttpClient(hc);
		h.addHeader("Host", THttpBase.getHost2(url));
		h.setListener(this);
		
		h.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, "0");		
	}
	
	public void scan() throws Exception {
		this.isCancelled = false;
		boolean isEmulator = AsyncManager.isEmulator();
		
		this.asyncManager.appendNetworkLog("isEmulator=" + isEmulator);
		
		if ( (isEmulator == true) ) {
			this.ipBase = PortScanner.EMULATOR_PREFIX;
			Log.d(tag, "Detected emulator, simulate ipBase=" + this.ipBase);
		} else {
			if (this.ipBase.equals("0.0.0.") == true) {
				this.asyncManager.appendNetworkLog("Cannot scan, no IP found and this is not emulator");
				throw new Exception("Cannot scan. This device is not connected to WIFI and this is not emulator.");	
			}
			
		}
		
		int i;
		
		if (this.ipBase.equals("localhost") == false) {
			for (i = 1; i < 256; i = i + this.chunkSize) {
				String url = "";
				url = this.getTestUrl(i);
				
				this.singleScan(String.valueOf(i) + ":" + String.valueOf(i), url);
			}
			
		} else {
			String url = this.getTestUrl(0);
			this.singleScan("localhost", url);
		}
		
		
	}
	
	private String getTestUrl(int i) {
		// i = postfix
		String url = "";
		
		if (AsyncManager.isEmulator() == false) {
			url = "http://" + this.ipBase + String.valueOf(i) + ":7778/stb/scan";	
		} else {
			if (this.ipBase.equals("localhost") == false) {
				url = "http://" + this.ipBase + String.valueOf(i) + ":7778/stb/scan";	
			} else {
				url = "http://" + this.ipBase + ":7778/stb/scan?a=1";
			}
			
		}
		
		return(url);
	}
	
	public void setListener(PortScannerListener l) {
		this.listener = l;
	}
	
	public void setChunkSize(int size) {
		this.chunkSize = size;
	}
	
	public int getChunkSize() {
		return(this.chunkSize);
	}

	@Override
	public void onProgressUpdate(THttpBase sender, Integer[] values) {
		
	}

	@Override
	public void onPostExecute(THttpBase sender, Long result) {

		String ipAddress = THttpBase.getHost2(sender.getUrl());
		this.count += 1;
		int activeCount = Thread.activeCount();
		Set<Thread> threadSet = Thread.getAllStackTraces().keySet();
		
		boolean b = false;
		if (result == 0l) {
			if (sender.getHttpResponse() != null) {
				b = true;
				
				if (sender.getHttpResponse().getStatusLine().getStatusCode() == 200) {
					
					String myIpAddress = THttpBase.getWiFiIPAddress(this.context);
					if (myIpAddress.equals(ipAddress) == false) {
						this.arrGoodIPs.add(ipAddress);
						Log.d(tag, "Added good ip:" + ipAddress);
						
						if (this.listener != null) {
							this.listener.onSingleCompleted(this, ipAddress, true, "OK");
							
						}						
					}
					
				} else {
					if (this.listener != null) {
						this.listener.onSingleCompleted(this, ipAddress, false, "HTTP:" + sender.getHttpResponse().getStatusLine().getStatusCode());
					}
				}
				
			}
			
		} else {  // executeHttp() raised Exception
			if (this.listener != null) {
				this.listener.onSingleCompleted(this, ipAddress, false, "executeHttp() raised Exception, could be Socket error");
			}
		}
		 
		
		if (this.ipBase.equals("localhost") ==  false) {
			int chunkId = Integer.valueOf(sender.getSessionName().split(":")[0]);
			int currentPostfix = Integer.valueOf(sender.getSessionName().split(":")[1]);
			if (currentPostfix+1 <= 255) {
				if (currentPostfix-chunkId < this.chunkSize-1) {
					String sessionName = String.valueOf(chunkId) + ":" + String.valueOf(currentPostfix+1);
					//String nextUrl = "http://" + this.ipBase + String.valueOf(currentPostfix+1);
					String nextUrl = this.getTestUrl(currentPostfix+1);
					if (this.isCancelled == false) {
						this.singleScan(sessionName, nextUrl);	
					}
					
				}	
			}
			
			Log.d(tag, "Got result (url=" + sender.getUrl() + ", has_http_response=" + b + ", sessionName=" + sender.getSessionName() + ", activeCount=" + activeCount + ", size=" + threadSet.size() + ", count=" + this.count + ")");
			
			if (this.count == 255) {
				if (this.listener != null) {
					this.listener.onComplete(this, this.arrGoodIPs);
				}
			}
			
		} else {  // This is localhost
			
			if (this.listener != null) {
				this.listener.onComplete(this, this.arrGoodIPs);
			}
		}
		
		
		
		
	}

	@Override
	public void onNewLineFetchBG(THttpBase sender, String line) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void onReceiveResponseBG(THttpBase sender) {

	}

	@Override
	public void onBinaryReadBG(THttpBase sender, byte[] b) {
		// TODO Auto-generated method stub
		
	}
	
	
}
